﻿using System;
namespace LinearAlgebra.VectorAlgebra
{
    /// <summary>
    /// 向量运算
    /// </summary>
    internal static class VectorComputation
    {
        /// <summary>
        /// 逐项取反
        /// </summary>
        internal static Vector UnaryMinus(Vector X)
        {
            int n = X.Count;
            var Z = new double[n];
            unsafe
            {
                fixed (double* x = X.Elements)
                fixed (double* z = Z)
                    for (int i = 0; i < n; i++)
                        z[i] = -x[i];
            }
            return new Vector(Z, X.vectorType);
        }
        internal static Vector Add(Vector X, Vector Y)
        {
            VectorCheck(X, Y);
            int n = X.Count;
            var Z = new double[n];
            unsafe
            {
                fixed (double* x = X.Elements)
                fixed (double* y = Y.Elements)
                fixed (double* z = Z)
                    for (int i = 0; i < n; i++)
                        z[i] = x[i] + y[i];
            }
            return new Vector(Z, X.vectorType);
        }
        internal static Vector Add(Vector X, double Scalar)
        {
            int count = X.Count;
            var Z = new double[count];
            unsafe
            {
                fixed (double* x = X.Elements)
                fixed (double* z = Z)
                    for (int i = 0; i < count; i++)
                    {
                        z[i] = x[i] + Scalar;
                    }
            }
            return new Vector(Z, X.vectorType);
        }
        internal static Vector Add(double Scalar, Vector X)
        {
            return Add(Scalar, X);
        }

        /// <summary>
        /// 逐项相减
        /// </summary>
        internal static Vector Subtract(Vector X, Vector Y)
        {
            VectorCheck(X, Y);
            int n = X.Count;
            var Z = new double[n];
            unsafe
            {
                fixed (double* x = X.Elements)
                fixed (double* y = Y.Elements)
                fixed (double* z = Z)
                    for (int i = 0; i < n; i++)
                        z[i] = x[i] - y[i];
            }
            return new Vector(Z, X.vectorType);
        }

        /// <summary>
        /// 每项都减去一个值
        /// </summary>
        internal static Vector Subtract(Vector X, double Scalar)
        {
            return Add(X, -Scalar);
        }
        /// <summary>
        /// z[i] = Scalar - x[i];
        /// </summary>
        internal static Vector Subtract(double Scalar,Vector X)
        {
            int count = X.Count;
            var Z = new double[count];
            unsafe
            {
                fixed (double* x = X.Elements)
                fixed (double* z = Z)
                    for (int i = 0; i < count; i++)
                    {
                        z[i] = Scalar - x[i];
                    }
            }
            return new Vector(Z, X.vectorType);
        }




        /// <summary>
        /// 逐项相乘
        /// </summary>
        internal static Vector Multiply(Vector X, Vector Y)
        {
            VectorCheck(X, Y);
            int n = X.Count;
            var Z = new double[n];
            unsafe
            {
                fixed (double* x = X.Elements)
                fixed (double* y = Y.Elements)
                fixed (double* z = Z)
                    for (int i = 0; i < n; i++)
                        z[i] = x[i] * y[i];
            }
            return new Vector(Z, X.vectorType);
        }
        /// <summary>
        /// 代数乘法
        /// </summary>
        internal static Vector Multiply(Vector X, double Scalar)
        {
            int count = X.Count;
            var Z = new double[count];
            unsafe
            {
                fixed (double* x = X.Elements)
                fixed (double* z = Z)

                    for (int i = 0; i < count; i++)
                    {
                        z[i] = x[i] * Scalar;
                    }
            }
            return new Vector(Z, X.vectorType);
        }


        /// <summary>
        /// 逐项相除
        /// </summary>
        internal static Vector Divide(Vector X, Vector Y)
        {
            VectorCheck(X, Y);
            int n = X.Count;
            var Z = new double[n];
            unsafe
            {
                fixed (double* x = X.Elements)
                fixed (double* y = Y.Elements)
                fixed (double* z = Z)
                    for (int i = 0; i < n; i++)
                        z[i] = x[i] / y[i];
            }
            return new Vector(Z, X.vectorType);
        }
        /// <summary>
        /// 遍历向量的每一项并进行修改
        /// </summary>
        internal static Vector Map(Vector X, Func<double, double> func)
        {
            int n = X.Count;
            var Z = new double[n];
            unsafe
            {
                fixed (double* x = X.Elements)
                fixed (double* z = Z)
                    for (int i = 0; i < n; i++)
                        z[i] = func(x[i]);
            }
            return new Vector(Z, X.vectorType);
        }
        /// <summary>
        /// 检查向量的长度和类型（行向量列向量）
        /// </summary>
        private static void VectorCheck(Vector X, Vector Y)
        {
            if (X.Count != Y.Count)
                throw new ArgumentException("进行运算的两个向量的长度必须一致");
            if (X.vectorType != Y.vectorType)
                throw new ArgumentException("进行运算的两个向量的类型必须一致");
        }
        /// <summary>
        /// 点乘
        /// </summary>
        internal static double DotProduct(Vector X, Vector Y)
        {
            VectorCheck(X, Y);
            double sum = 0.0;
            unsafe
            {
                fixed (double* x = X.Elements)
                fixed (double* y = Y.Elements)
                    for (int i = X.Count - 1; i >= 0; i--)
                        sum += x[i] * y[i];
            }
            return sum;
        }
    }
}
